/**
 * Copyright &copy; 2012-2016 <a href="https://github.com/thinkgem/jeesite">JeeSite</a> All rights reserved.
 */
package com.anuo.app.common.utils;

import com.fasterxml.jackson.annotation.JsonInclude.Include;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.core.JsonParser.Feature;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.util.JSONPObject;
import com.fasterxml.jackson.module.jaxb.JaxbAnnotationModule;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import org.apache.commons.lang3.StringEscapeUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.List;
import java.util.Map;
import java.util.TimeZone;

/**
 * Json工具类(简单封装Jackson)
 */
public class JsonUtil extends ObjectMapper {

    private static Logger logger = LoggerFactory.getLogger(JsonUtil.class);

    private static final long serialVersionUID = 1L;


    //region 获取当前类实例
    private static JsonUtil mapper;
    private static final Object object = new Object();
    public static JsonUtil getInstance() {
        if (mapper == null) {
            synchronized (object) {
                if (mapper == null) {
                    mapper = new JsonUtil().configure();
                }
            }
        }
        return mapper;
    }

    //endregion 获取当前类实例


    private JsonUtil() {
        this(Include.NON_EMPTY);

    }

    private JsonUtil(Include include) {
        // 设置输出时包含属性的风格
        if (include != null) {
            this.setSerializationInclusion(include);
        }
        // 允许单引号、允许不带引号的字段名称等配置
        this.configure();
        // 设置输入时忽略在JSON字符串中存在但Java对象实际没有的属性
        this.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
        // 空值处理为空串
        this.getSerializerProvider().setNullValueSerializer(new JsonSerializer<Object>() {
            @Override
            public void serialize(Object value, JsonGenerator jgen,
                                  SerializerProvider provider) throws IOException {
                jgen.writeString("");
            }
        });
        // 进行HTML解码。
        this.registerModule(new SimpleModule().addSerializer(String.class, new JsonSerializer<String>() {
            @Override
            public void serialize(String value, JsonGenerator jgen,
                                  SerializerProvider provider) throws IOException {
                jgen.writeString(StringEscapeUtils.unescapeHtml4(value));
            }
        }));
        // 设置时区
        this.setTimeZone(TimeZone.getDefault());//getTimeZone("GMT+8:00")


    }

    /**
     * 允许单引号
     * 允许不带引号的字段名称
     * 大小写不敏感
     */
    public JsonUtil configure() {
        this.configure(Feature.ALLOW_SINGLE_QUOTES, true);
        this.configure(Feature.ALLOW_UNQUOTED_FIELD_NAMES, true);
        //大小写不敏感
        this.configure(MapperFeature.ACCEPT_CASE_INSENSITIVE_PROPERTIES, true);
        return this;
    }


    public static String toJson(Object object) {
        try {
            return JsonUtil.getInstance().writeValueAsString(object);
        } catch (IOException e) {
            logger.warn("write to json string error:" + object, e);
            return null;
        }
    }


    public static String toJsonPretty(Object object) {

        try {
            return JsonUtil.getInstance()
                    .writerWithDefaultPrettyPrinter()
                    .writeValueAsString(object);
        } catch (IOException e) {
            logger.warn("write to json string error:" + object, e);
            return null;
        }
    }

    /**
     * 反序列化POJO或简单Collection如List<String>.
     * <p>
     * 如果JSON字符串为Null或"null"字符串, 返回Null.
     * 如果JSON字符串为"[]", 返回空集合.
     * <p>
     * 如需反序列化复杂Collection如List<MyBean>, 请使用fromJson(String,JavaType)
     *
     */
    public static <T> T fromJson(String jsonString, Class<T> clazz) {
        if (StringUtils.isEmpty(jsonString)) {
            return null;
        }
        try {
            return JsonUtil.getInstance().readValue(jsonString, clazz);
        } catch (IOException e) {
            logger.warn("parse json string error:" + jsonString, e);
            return null;
        }
    }

    /**
     * 反序列化
     */
    public static <T> T fromJson(String jsonString, TypeReference<T> type) {
        if (StringUtils.isEmpty(jsonString)) {
            return null;
        }
        T obj;
        try {
            obj = JsonUtil.getInstance().readValue(jsonString, type);
        } catch (IOException e) {
            logger.error("反序列化json 字符串报错 : " + jsonString, e);
            throw new RuntimeException("反序列化失败, 错误信息:" + e.toString());
        }
        return obj;

    }

    /**
     * 测试
     */
    public static void main(String[] args) {
        List<Map<String, Object>> list = Lists.newArrayList();
        Map<String, Object> map = Maps.newHashMap();
        map.put("id", 1);
        map.put("pId", -1);
        map.put("name", "根节点");
        list.add(map);
        map = Maps.newHashMap();
        map.put("id", 2);
        map.put("pId", 1);
        map.put("name", "你好");
        map.put("open", true);
        list.add(map);
        String json = JsonUtil.toJson(list);
        System.out.println(json);
    }

    /**
     * 是否为有效的json
     *  参考: https://stackoverflow.com/questions/10226897/how-to-validate-json-with-jackson-json
     * @param json
     * @return
     * @throws IOException
     */
    public static boolean isValidJSON(final String json) throws IOException {
        boolean valid = true;
        try{
            JsonUtil.getInstance().readTree(json);
        } catch(JsonProcessingException e){
            valid = false;
        }
        return valid;
    }


}

